/*
 * SpeedoGradient - Speedometer and gradient  meter application for Android 
 * Copyright 2013 Guilhem VALENTIN
 * 
 * This file is part of SpeedoGradient
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with SpeedoGradient. If not, see <http://www.gnu.org/licenses/>.
 */
package com.gvalentin.speedogradient.data;

import android.location.Location;

/**
 * Calculate the speed from GPS data.
 * Speed is already provided by GPS data. This class will actually filter
 * invalid speed readings.
 * 
 * @author guilhem
 */
public class CalculatorSpeed implements Calculator<Double> {
	
	/** Calculated speed */
	private Double speed = 0.0d;

	
	/**
	 * Calculate updated speed
	 * Code inspired from Google Mytracks
	 * com.google.android.apps.mytracks.stats.TripStatisticsUpdater
     * http://code.google.com/p/mytracks/source/browse/MyTracks/src/com/google/android/apps/mytracks/stats/TripStatisticsUpdater.java
	 * @see com.gvalentin.SpeedoGradient.data.Calculator#update(android.location.Location, android.location.Location)
	 */
	@Override
	public void update(Location previous, Location current) {
		// Get speed from GPS
		if (current == null) {
			return;
		}
		double gpsSpeed = current.getSpeed();
		
	    // There are a lot of noisy speed readings. Do the cheapest checks first,
	    // most expensive last.
	    if (gpsSpeed < 0) {
	    	return;
	    }

	    // The following code will ignore unlikely readings. 128 m/s seems to be an
	    // internal android error code.
	    if (Math.abs(gpsSpeed - 128) < 1) {
	    	return;
	    }
	    
	    // Prevent sudden and irrealistic falls to 0
	    if (gpsSpeed == 0 &&
	    	previous != null && previous.getSpeed() > 5 /* m/s */) {
	    	return;
	    }
	  
	    // OK to use GPS speed
	    speed = gpsSpeed;
	}

	/**
	 * Return calculated speed
	 * @see com.gvalentin.SpeedoGradient.data.Calculator#getData()
	 */
	@Override
	public Double getData() {
		return speed;
	}

}
